package test.zookeeper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import lombok.Data;

public class Watch {
	
	private Node root = new Node();
	
	public Watch() {
		root.path = "/root";
	}
	
	enum Event {
		NodeCreated,
        NodeDeleted,
        NodeDataChanged,
        NodeChildrenCreated,
		NodeChildrenDeleted;
	}
	
	interface Watcher {
		void process(Event event);
	}
	
	private Map<String, List<Watcher>> getDataWatcherMap = new HashMap<>();
	private Map<String, List<Watcher>> getChildrenWatcherMap = new HashMap<>();
	
	@Data
	class Node {
		private Node parent;
		private String path;
		private String value;
		private List<Node> children = new ArrayList<>();
		public String toString() {
			return "Node[path=" + path + ",value=" + value + "]";
		}
	}
	
	public String getData(String path, Watcher watcher) {
		List<Watcher> list = getDataWatcherMap.get(path);
		if(list==null) {
			list = new ArrayList<>();
		}
		list.add(watcher);
		getDataWatcherMap.put(path, list);
		
		Node node = findNode(path);
		if(node!=null) {
			return node.value;
		}
		return null;
	}
	
	public List<String> getChildren(String path, Watcher watcher) {
		List<Watcher> list = getChildrenWatcherMap.get(path);
		if(list==null) {
			list = new ArrayList<>();
		}
		list.add(watcher);
		getChildrenWatcherMap.put(path, list);
		
		Node node = findNode(path);
		if(node==null) {
			return Collections.emptyList();
		} else {
			List<Node> nodes = node.children;
			return nodes.stream().map(new Function<Node, String>() {
				@Override
				public String apply(Node t) {
					return t.path;
				}
			}).collect(Collectors.toList());
		}
	}
	
	public void setData(String path, String value) {
		Node node = findNode(path);
		if(node==null) {
			throw new RuntimeException("节点不存在！！！");
		}
		node.value = value;
		List<Watcher> getDataWatcherList = getDataWatcherMap.get(path);
		if(getDataWatcherList!=null) {
			Iterator<Watcher> iter = getDataWatcherList.iterator();
			while(iter.hasNext()) {
				Watcher watcher = iter.next();
				watcher.process(Event.NodeDataChanged);
				iter.remove();
			}
		}
	}
	
	public void create(String path, String value) {
		int index = path.lastIndexOf("/");
		String parentPath = path.substring(0, index);
		Node parent = findNode(parentPath);
		if(parent!=null) {
			Node node = new Node();
			node.parent = parent;
			node.path = path;
			node.value = value;
			parent.children.add(node);
			
			List<Watcher> getDataWatcherList = getDataWatcherMap.get(path);
			if(getDataWatcherList!=null) {
				Iterator<Watcher> iter = getDataWatcherList.iterator();
				while(iter.hasNext()) {
					Watcher watcher = iter.next();
					watcher.process(Event.NodeCreated);
					iter.remove();
				}
			}
			
			List<Watcher> getChildrenWatcherList = getChildrenWatcherMap.get(parentPath);
			if(getChildrenWatcherList!=null) {
				Iterator<Watcher> iter = getChildrenWatcherList.iterator();
				while(iter.hasNext()) {
					Watcher watcher = iter.next();
					watcher.process(Event.NodeChildrenCreated);
					iter.remove();
				}
			}
			
		} else {
			throw new RuntimeException("父节点不存在！！");
		}
	}
	
	public Node findNode(String path) {
		if(path.equals("/root")) {
			return root;
		}
		return findNode(root, path);
	}
	
	public Node findNode(Node node, String path) {
		while(true) {
			List<Node> list = node.children;
			for(Node n : list) {
				if(n.path.equals(path)) {
					return n;
				} else {
					Node temp = findNode(n, path);
					if(temp!=null) {
						return temp;
					}
				}
			}
			return null;
		}
	}
	
	public void delete(String path) {
		Node node = findNode(path);
		if(node==null) {
			return;
		}
		
		List<Watcher> getDataWatcherList = getDataWatcherMap.get(path);
		if(getDataWatcherList!=null) {
			Iterator<Watcher> iter = getDataWatcherList.iterator();
			while(iter.hasNext()) {
				Watcher watcher = iter.next();
				watcher.process(Event.NodeDeleted);
				iter.remove();
			}
		}
		
		List<Watcher> getChildrenWatcherList = getChildrenWatcherMap.get(node.parent.path);
		if(getChildrenWatcherList!=null) {
			Iterator<Watcher> iter = getChildrenWatcherList.iterator();
			while(iter.hasNext()) {
				Watcher watcher = iter.next();
				watcher.process(Event.NodeChildrenDeleted);
				iter.remove();
			}
		}
		
		node.parent.children.remove(node);
		node.parent = null;
		node = null;
	}
	
	public static void main(String[] args) {
		Watch watch = new Watch();
		
		String data = watch.getData("/root/hello/ttt", new Watcher() {
			@Override
			public void process(Event event) {
				System.out.println(event.name());
			}
		});
		System.out.println(data);
		
		
		watch.create("/root/hello", "");
		watch.create("/root/hello/ttt", "bbq");
		
		String data2 = watch.getData("/root/hello/ttt", new Watcher() {
			@Override
			public void process(Event event) {
				System.out.println(event.name());
			}
		});
		System.out.println(data2);
		
		List<String> list = watch.getChildren("/root/hello", new Watcher() {
			@Override
			public void process(Event event) {
				System.out.println(event.name());
			}
		});
		System.out.println(list);
		
		watch.delete("/root/hello/ttt");
		
	}
	
	

}
